#include <curl/curl.h>

#include "response.hpp"
#include "request.hpp"
#include "apollo_client.hpp"

namespace apollo
{
void to_json(nlohmann::json &j, const Response &response)
{
    j = nlohmann::json{{"appId", response.appId}, {"cluster", response.cluster},
        {"namespaceName", response.namespaceName}, {"releaseKey", response.releaseKey},
        {"configurations", response.configurations}};
}

void from_json(const nlohmann::json &j, Response &response)
{
    j.at("appId").get_to(response.appId);
    j.at("cluster").get_to(response.cluster);
    j.at("namespaceName").get_to(response.namespaceName);
    j.at("releaseKey").get_to(response.releaseKey);
    if(j.at("configurations").find("content") != j.at("configurations").end()) {
        j.at("configurations").at("content").get_to(response.configurations);
    } else {
        j.at("configurations").get_to(response.configurations);
    }
}

static size_t write_callback(
    void *input, size_t uSize,
    size_t uCount, void *data)
{

    size_t uLen = uSize * uCount;
    std::string &sBuffer = *reinterpret_cast<std::string*>(data);
    sBuffer.append(reinterpret_cast<const char *>(input), uLen);

    // 只有返回uSize*uCount才会返回成功
    return uLen;
}

/**
 * @brief getProperties
 * @param request
 * @return response
 */
Response ApolloClient::getProperties(const Request &request) {
    return getConfigFromServer(request, configSuffix::PROPERTIES);
}

/**
 * @brief getJson
 * @param request
 * @return
 */
Response ApolloClient::getJson(const Request &request) {
    return getConfigFromServer(request, configSuffix::JSON);
}

/**
* @brief getTxt
* @param request
* @return
 */
Response ApolloClient::getTxt(const Request &request) {
    return getConfigFromServer(request, configSuffix::TXT);
}

/**
 * @brief getYaml
 * @param request
 * @return
 */
Response ApolloClient::getYaml(const Request &request) {
    return getConfigFromServer(request, configSuffix::YAML);
}

/**
 * @brief getConfigFromServer
 * @param request
 * @return response
 */
Response ApolloClient::getConfigFromServer(const Request &request, const configSuffix& suffix)
{
    Response response;
    CURL *curl = curl_easy_init();
    if (curl == NULL)
    {
        std::cout << "curl_easy_init() Err" << std::endl;
        return response;
    }
    CURLcode curl_res;
    std::stringstream sstream;
    sstream << request.getServerUrl() << "/"
            << "configs/"
            << request.getAppId() << "/"
            << request.getClusterName() << "/"
            << request.getNamespace() << getSuffixStr(suffix);
    std::string urlDest = sstream.str();
    std::string data;
    curl_easy_setopt(curl, CURLOPT_URL, urlDest.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
    curl_res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);

    if (curl_res == CURLE_OK)
    {
        nlohmann::json j = nlohmann::json::parse(data);
        return j.get<Response>();
    }
    else
    {
        std::cout << "curl_easy_perform() Err \n";
        return response;
    }
}
} // namespace apollo
